package com.jhg.drgclinicalpathway.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.data.ChartMultiSeriesRenderData;
import com.deepoove.poi.data.ChartSingleSeriesRenderData;
import com.deepoove.poi.data.Charts;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.deepoove.poi.util.PoitlIOUtils;
import com.jhg.drgclinicalpathway.dao.CostAnalysisDao;
import com.jhg.drgclinicalpathway.domain.入径统计;
import lombok.Data;
import org.apache.commons.math3.stat.descriptive.summary.Sum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;


@Service
public class ReportWordService {

    public void gener(Map<String,String> reqMap,HttpServletRequest req, HttpServletResponse rep) throws Exception {
        ClassPathResource resource = new ClassPathResource("/tpl/wordTpl.docx");
        // 2.判断模板是否存在
        if (!resource.exists()) {
            throw new RuntimeException(resource.getFilename()+" 没找到！");
        }

        // 3.用数据填充模板
        InputStream wordTmpl = resource.getInputStream();

        // 获取单位名称
        ConfigureBuilder builder = Configure.builder();
        builder.useSpringEL(false);
        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
        builder.bind("countLs", policy);
        //生成参数
        Map<String, Object> params=generParams(reqMap);
        XWPFTemplate template = XWPFTemplate.compile(wordTmpl, builder.build()).render(params);
        // 4.关闭模板文档
        wordTmpl.close();
        // 5.以网络流形式输出
        rep.setContentType("application/octet-stream");
        rep.setCharacterEncoding("UTF-8");
        String fileName =new String("报告模板".getBytes("UTF-8"), "iso-8859-1") ;
        rep.setHeader("Content-disposition",
                "attachment;filename=" + fileName+ ".docx");
        // HttpServletResponse response
        rep.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        OutputStream out = rep.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(out);
        template.write(bos);
        bos.flush();
        out.flush();
        PoitlIOUtils.closeQuietlyMulti(template, bos, out);
        template.close();
    }

    private String 时间处理(String time,String key,String fmtStr){
        String stime = time;

        SimpleDateFormat fmt=new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        try {
            date=fmt.parse(stime);
        }catch (Exception ex){}

        return new SimpleDateFormat(fmtStr).format(date);
    }
    private String 开始日期(Map<String,String> reqMap){
       return 时间处理(reqMap.get("stime"),"stime","yyyy-MM");
    }
    private String 结束时间日期(Map<String,String> reqMap){
        return 时间处理(reqMap.get("etime"),"etime","yyyy-MM");
    }
    private Map<String,Object> generParams(Map<String,String>reqMap){
        Map<String,Object> map=new HashMap<>();

        String stime=开始日期(reqMap);
        String etime=结束时间日期(reqMap);
        //报告上显示的时间
        String reportTime=stime;
        if(!reportTime.equals(etime)){
            reportTime+="至"+etime;
        }
        map.put("rptime",reportTime);
        String 开始时间=reqMap.get("stime");
        String 结束时间=reqMap.get("etime");

        List<PathWordView> 入径统计按时间 = 入径统计按时间(开始时间, 结束时间,map);
        String 开始时间处理 = 时间处理(日期加年(开始时间, -1), "", "yyyy-MM");
        String 结束时间处理 = 时间处理(日期加年(结束时间, -1), "", "yyyy-MM");
        if(开始时间处理.equals(结束时间处理)){
            map.put("prptime",开始时间处理);
        }else{
            map.put("prptime",开始时间处理+"至"+结束时间处理);
        }
        map.put("countLs",入径统计按时间);

        生成图表(map,开始时间,结束时间);
        for (Map.Entry<String, String> entry : reqMap.entrySet()) {
            if(!StringUtils.isEmpty(entry.getValue())){
                map.put(entry.getKey(),entry.getValue());
            }

        }

        map.put("curtime",new SimpleDateFormat("yyyy-MM-dd").format(new Date()));

        return map;
    }


    public void 月度趋势图(Map<String,Object> map,String stime,String etime){
        List<入径统计> 月度统计Ls = costAnalysisDao.月度统计(stime, etime);

        List<String> keys=new ArrayList<>();
        Map<String,List<Double>> 数据Map=new HashMap<>();
        Map<String,Integer> totalMap=new HashMap<>();

        for (入径统计 月度统计 : 月度统计Ls) {
            Integer 病人数=月度统计.getCount();
            Integer 入径人数=月度统计.getGrp();
            Integer 变异人数=月度统计.getSfby();
            Integer 完成人数=月度统计.getFinish();
            String k=月度统计.getName()+"月";

            totalMap.put("病人数",totalMap.getOrDefault("病人数",0)+病人数);
            totalMap.put("入径人数",totalMap.getOrDefault("入径人数",0)+入径人数);
            totalMap.put("变异人数",totalMap.getOrDefault("变异人数",0)+变异人数);
            totalMap.put("完成人数",totalMap.getOrDefault("完成人数",0)+完成人数);

            Double 入径率=0.00,变异率=0.00,完成率=0.00;
            if(病人数>0){
                入径率=入径人数*1.0/病人数*100;
                变异率=变异人数*1.0/病人数*100;
            }
            if(入径人数>0) 完成率=完成人数*1.0/入径人数*100;

            for(String kk:new String[]{"入径率","变异率","完成率"}){
                List<Double> Ls = 数据Map.getOrDefault(kk, new ArrayList<>());
                if(数据Map.get(kk)==null) 数据Map.put(kk,Ls);
                Double r=0.00;
                switch (kk){
                    case "入径率":r=入径率;break;
                    case "变异率":r=变异率;break;
                    case "完成率":r=完成率;break;
                }
                r=Double.parseDouble(小数处理(r));
                Ls.add(r);
            }
            keys.add(k);
        }
        keys.add("汇总");

        Charts.ChartCombos 月度统计 = Charts.ofComboSeries("临床路径管理率标", keys.toArray(new String[0]));

        for (Map.Entry<String, List<Double>> entry : 数据Map.entrySet()) {
            String key = entry.getKey();
            Integer 病人数=totalMap.getOrDefault("病人数",0);
            Integer 入径人数=totalMap.getOrDefault("入径人数",0);
            Integer 变异人数=totalMap.getOrDefault("变异人数",0);
            Integer 完成人数=totalMap.getOrDefault("完成人数",0);
            double r=0.00;
            switch (key){
                case "入径率":
                    if(病人数>0) r=入径人数*1.0/病人数*100;
                    break;
                case "变异率":
                    if(病人数>0)r=变异人数*1.0/病人数*100;
                    break;
                case "完成率":
                    if(入径人数>0) r=完成人数*1.0/入径人数*100;
                    break;
            }
            r=Double.parseDouble(小数处理(r));
            entry.getValue().add(r);

            月度统计.addBarSeries(entry.getKey(),entry.getValue().toArray(new Double[0]));
        }
        map.put("monthchart",月度统计.create());
    }


    public void 生成图表(Map<String,Object> map,String stime,String etime){

        List<入径统计> 科室入组统计Ls = costAnalysisDao.科室入组统计(stime, etime);
        //List<String> ksLs = 科室入组统计Ls.stream().map(it -> it.getKs()).distinct().collect(Collectors.toList());
       Map<String,List<Object>> valueMap=new HashMap<>();
       List<String> ksLs=new ArrayList<>();

        for (入径统计 l : 科室入组统计Ls) {
            //病人数
            Integer 病人数 = l.getCount();
            Integer 入径人数 = l.getGrp();
            Integer 完成人数 = l.getFinish();
            Integer 变异人数 = l.getSfby();


            Double 入径率=0D;
            if(病人数>0) 入径率=入径人数*1.0/病人数*100;
            Double 变异率=0D;
            if(病人数>0){
                变异率=变异人数*1.0/病人数*100;
            }

            Double 完成率=0D;
            if(入径人数>0) 完成率=完成人数*1.0/入径人数*100;

            完成率=Double.parseDouble(小数处理(完成率));
            入径率=Double.parseDouble(小数处理(入径率));
            变异率=Double.parseDouble(小数处理(变异率));

            //--------构建病人数
            List<Object> 病人数Ls = valueMap.get("病人数");
            if(病人数Ls==null){
                病人数Ls=new ArrayList<>();
                valueMap.put("病人数",病人数Ls);
            }
            病人数Ls.add(病人数);

            //-------入径人数
            List<Object> 入径人数Ls = valueMap.get("入径人数");
            if(入径人数Ls==null){
                入径人数Ls=new ArrayList<>();
                valueMap.put("入径人数",入径人数Ls);
            }
            入径人数Ls.add(入径人数);
            //-------完成人数
            List<Object> 完成人数Ls = valueMap.get("完成人数");
            if(完成人数Ls==null){
                完成人数Ls=new ArrayList<>();
                valueMap.put("完成人数",完成人数Ls);
            }
            完成人数Ls.add(完成人数);

            //-------变异人数
            List<Object> 变异人数Ls = valueMap.get("变异人数");
            if(变异人数Ls==null){
                变异人数Ls=new ArrayList<>();
                valueMap.put("变异人数",变异人数Ls);
            }
            变异人数Ls.add(变异人数);

            //-------变异率
            List<Object> 变异率Ls = valueMap.get("变异率");
            if(变异率Ls==null){
                变异率Ls=new ArrayList<>();
                valueMap.put("变异率",变异率Ls);
            }
            变异率Ls.add(变异率);

            //-------完成率
            List<Object> 完成率Ls = valueMap.get("完成率");
            if(完成率Ls==null){
                完成率Ls=new ArrayList<>();
                valueMap.put("完成率",完成率Ls);
            }
            完成率Ls.add(完成率);

            //-------完成率
            List<Object> 入径率Ls = valueMap.get("入径率");
            if(入径率Ls==null){
                入径率Ls=new ArrayList<>();
                valueMap.put("入径率",入径率Ls);
            }
            入径率Ls.add(入径率);

            ksLs.add(l.getKs());
        }

        ksLs.add("汇总");

        Charts.ChartCombos 科室统计 = Charts.ofComboSeries("科室统计", ksLs.toArray(new String[0]));
        Map<String,Integer> 人数Map=new HashMap<>();
        for (Map.Entry<String, List<Object>> entry : valueMap.entrySet()) {
            if(entry.getKey().indexOf("人数")>-1){
                int sum=0;
                for (Object o : entry.getValue()) {
                    sum+=((Integer)o).intValue();
                }
                人数Map.put(entry.getKey(),sum);
                entry.getValue().add(sum);
                科室统计.addBarSeries(entry.getKey(),entry.getValue().toArray(new Integer[0]));
            }

        }
        for (Map.Entry<String, List<Object>> entry : valueMap.entrySet()) {

            if(entry.getKey().indexOf("人数")<0){
                double r=0;
                switch (entry.getKey()){
                    case "入径率":
                        Integer 病人数=人数Map.getOrDefault("病人数",0);
                        Integer 入径人数=人数Map.getOrDefault("入径人数",0);
                        if(病人数>0) r=入径人数*1.0/病人数*100;
                        break;
                    case "变异率":
                        Integer 病人数2=人数Map.getOrDefault("病人数",0);
                        Integer 变异人数=人数Map.getOrDefault("变异人数",0);
                        if(病人数2>0) r=变异人数*1.0/病人数2*100;
                        break;
                    case "完成率":
                        Integer 入径人数2=人数Map.getOrDefault("入径人数",0);
                        Integer 完成人数2=人数Map.getOrDefault("完成人数",0);
                        if(入径人数2>0) r=完成人数2*1.0/入径人数2*100;
                        break;
                }
                r=Double.parseDouble(小数处理(r));
                entry.getValue().add(r);
                科室统计.addLineSeries(entry.getKey(), entry.getValue().toArray(new Double[0]));
            }
        }


        map.put("kschart",科室统计.create());


        月度趋势图(map,stime,etime);

    }

    @Autowired
    CostAnalysisDao costAnalysisDao;

    public String 日期加年(String time,int year){
        SimpleDateFormat fmt=new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        try {
            date=fmt.parse(time);
        }catch (Exception ex){}

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);   //设置当前时间
        cal.add(Calendar.YEAR, year);  //在当前时间基础上加一年
        return fmt.format(cal.getTime());
    }
    public List<PathWordView> 入径统计按时间(String stime,String etime,Map<String,Object> ps){

        List<PathWordView> 结果Ls=new ArrayList<>();
        //本期
        List<入径统计> 本期Ls = costAnalysisDao.入径统计By时间(stime, etime);
        //同
        List<入径统计> 同期Ls = costAnalysisDao.入径统计By时间(日期加年(stime, -1), 日期加年(etime, -1));

//        System.out.println("本期："+stime + "=>" + etime);
//        System.out.println("同期："+日期加年(stime, -1) + "=>" + 日期加年(etime, -1));
        PathWordView total=new PathWordView();
        total.setName("合计");
        int 同期Count=0;
        for (入径统计 one : 本期Ls) {
            String name = one.getName();
            PathWordView pwv=new PathWordView();
            pwv.setName(name);
            pwv.setCurPatCount(one.getCount());
            pwv.setCurGrpCount(one.getGrp());
            pwv.setCurBed(one.getBed());
            pwv.setCurCost(one.getCost());
            pwv.setCurFinish(one.getFinish());
            pwv.setCurfhd(one.getFhd());
            pwv.setCurzcry(one.getZcry());
            pwv.setCursfby(one.getSfby());

            total.setCurPatCount(total.getCurPatCount()+pwv.getCurPatCount());
            total.setCurGrpCount(total.getCurGrpCount()+pwv.getCurGrpCount());
            total.setCurBed(total.getCurBed()+pwv.getCurBed());
            total.setCurCost(total.getCurCost()+pwv.getCurCost());
            total.setCurFinish(total.getCurFinish()+pwv.getCurFinish());
            total.setCurfhd(total.getCurfhd()+pwv.getCurfhd());
            total.setCurzcry(total.getCurzcry()+pwv.getCurzcry());
            total.setCursfby(total.getCursfby()+pwv.getCursfby());

            Optional<入径统计> first = 同期Ls.stream().filter(it -> it.getName().equals(name)).findFirst();
            if (first.isPresent()) {
                入径统计 同期Item = first.get();
                pwv.setPreGrpCount(同期Item.getGrp());
                pwv.setPrePatCount(同期Item.getCount());
                pwv.setPreBed(同期Item.getBed());
                pwv.setPreCost(同期Item.getCost());
                pwv.setPreFinish(同期Item.getFinish());
                pwv.setPrefhd(同期Item.getFhd());
                pwv.setPrezcry(同期Item.getZcry());
                pwv.setPresfby(同期Item.getSfby());
                total.setPreGrpCount(total.getPreGrpCount()+pwv.getPreGrpCount());
                total.setPrePatCount(total.getPrePatCount()+pwv.getPrePatCount());
                total.setPreBed(total.getPreBed()+pwv.getPreBed());
                total.setPreCost(total.getPreCost()+pwv.getPreCost());
                total.setPreFinish(total.getPreFinish()+pwv.getPreFinish());
                total.setPrefhd(total.getPrefhd()+pwv.getPrefhd());
                total.setPrezcry(total.getPrezcry()+pwv.getPrezcry());
                total.setPresfby(total.getPresfby()+pwv.getPresfby());
                同期Count++;
            }
            界面百分比处理(pwv);
            结果Ls.add(pwv);
        }
        if(同期Count>0){
            total.setPrefhd(total.getPrefhd()/同期Count);
        }

        if(本期Ls.size()>0){
            total.setCurfhd(total.getCurfhd()/本期Ls.size());
        }

        界面百分比处理(total);

        if(本期Ls.size()>0) 结果Ls.add(total);
        ps.put("total",total);
        return 结果Ls;
    }

    private void 界面百分比处理(PathWordView pwv){

        //病历增长率
        pwv.setPatCountAddRate(增长率(pwv.getCurPatCount(),pwv.getPrePatCount()));
        //入径增长率
        pwv.setGrpAddRate(增长率(pwv.getCurGrpCount(),pwv.getPreGrpCount()));
        //本期入径率
        pwv.setCurGrpRate(百分比(pwv.getCurGrpCount(),pwv.getCurPatCount()));
        //同期入径率
        pwv.setPreGrpRate(百分比(pwv.getPreGrpCount(),pwv.getPrePatCount()));
        //本期完成率
        pwv.setCurFinishRate(百分比(pwv.getCurFinish(),pwv.getCurGrpCount()));
        pwv.setPreFinishRate(百分比(pwv.getPreFinish(),pwv.getPreGrpCount()));

        //本期变异率
        pwv.setCursfbyRate(百分比(pwv.getCursfby(),pwv.getCurPatCount()));
        pwv.setPresfbyRate(百分比(pwv.getPresfby(),pwv.getPrePatCount()));

        //同期平均住院床日
        pwv.setCurBedAvg(平均值(pwv.getCurBed(),pwv.getCurPatCount()));
        pwv.setCurCostAvg(平均值(pwv.getCurCost(),pwv.getCurPatCount()));
        pwv.setPreBedAvg(平均值(pwv.getPreBed(),pwv.getPrePatCount()));
        pwv.setPreCostAvg(平均值(pwv.getPreCost(),pwv.getPrePatCount()));

        //本期符合度
        pwv.setCurfhdRate(小数处理(pwv.getCurfhd()));
        pwv.setPrefhdRate(小数处理(pwv.getPrefhd()));
        //30天再入院
        pwv.setCurzcryRate(百分比(pwv.getCurzcry(),pwv.getCurPatCount()));
        pwv.setPrezcryRate(百分比(pwv.getPrezcry(),pwv.getPrePatCount()));
    }

    private String 平均值(Double a,Integer b){
        if(a==null||b==null) return "0";
        if(b==0) return "0";
        return String.format("%.2f",a/b);
    }

    private String 增长率(Integer a,Integer b){
        if(a==null) a=0;
        if(b==null) b=0;
        a=a-b;
        return 百分比(a,b);
    }
    private String 小数处理(Double f){
        double f2=0;
        if(f!=null) f2=f.doubleValue();
        return String.format("%.2f",f2);

    }
    private String 百分比(Integer a,Integer b){

        if(a==null||b==null) return "";
        if(b==0) return "0";
        return String.format("%.2f",a*1.0/b*100);

    }


    //临床路径统计表
    @Data
    private class PathWordView{
        //路径名称
        private String name;
        //本期病历数
        private Integer curPatCount=0;
        //同期病历数
        private Integer prePatCount=0;

        //增长率
        private String patCountAddRate;

        //本期入组数
        private Integer curGrpCount=0;
        //同期入组数
        private Integer preGrpCount=0;
        //增长率
        private String grpAddRate;

        //入径率

        //本期入径率
        private String curGrpRate;
        //同期入径率
        private String preGrpRate;

        //本期平均床日
        private String curBedAvg;
        //同期平均床日
        private String preBedAvg;

        //本期平均费用
        private String curCostAvg;
        //同期平均费用
        private String preCostAvg;

        //路径完成
        private Integer curFinish=0;
        private Integer preFinish=0;
        //完成率
        private String curFinishRate;
        private String preFinishRate;

        //符合度
        private double curfhd=0;
        private double prefhd=0;
        //30天内再入院
        private Integer curzcry=0;
        private Integer prezcry=0;
        //符合率
        private String curfhdRate;
        private String prefhdRate;
        //30天内再入院率
        private String curzcryRate;
        private String prezcryRate;

        //本期变异
        private Integer cursfby=0;
        private String cursfbyRate;
        //同期变异
        private Integer presfby=0;
        private String presfbyRate;

        private Double curBed=0.0;
        private Double preBed=0.0;
        private Double curCost=0.0;
        private Double preCost=0.0;
    }
}
